////////////////////////////////////////////////////////////////////////////////
/*!	\file		
**	\brief		
**	\author		Nate Cleveland
**	\date		2/7/2003 2:05:40 PM
**	\par		DESCRIPTION:
**					
**	\par		REMARKS:
**					
*/
////////////////////////////////////////////////////////////////////////////////
#pragma warning(disable: 4786)
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <conio.h>
#include <time.h>
#include "testC45.hpp"
using namespace std;
using namespace DTree;

//!Disable poor performance warning about forcing an int to 'true' or 'false'.
#pragma warning(disable: 4800)



////////////////////////////////////////////////////////////////////////////////
//	FUNCTION:	CreateExample
/*!	\brief		Creates an example for a Dtree relative to current operation.
**	\author		Nate Cleveland
*/
////////////////////////////////////////////////////////////////////////////////
void CreateExample(vector<float>& caseVec, bool& result, char type__)
{
	caseVec.clear();
	caseVec.push_back(static_cast<float>(rand()%2));
	caseVec.push_back(static_cast<float>(rand()%2));

	switch(type__)
	{
	case '%':	//triple xor.
		caseVec.push_back(static_cast<float>(rand()%2));
		if(static_cast<int>(caseVec[0]) && !(static_cast<int>(caseVec[1])) && !(static_cast<int>(caseVec[2])))
			result = true;
		else if(!(static_cast<int>(caseVec[0])) && (static_cast<int>(caseVec[1])) && !(static_cast<int>(caseVec[2])))
			result = true;
		else if(!(static_cast<int>(caseVec[0])) && !(static_cast<int>(caseVec[1])) && (static_cast<int>(caseVec[2])))
			result = true;
		else
			result = false;
		break;


	case '^':
		result = static_cast<int>(caseVec[0]) ^ static_cast<int>(caseVec[1]);
		break;


	case '#':	//triple or.
		caseVec.push_back(static_cast<float>(rand()%2));
		if((static_cast<int>(caseVec[0])) || (static_cast<int>(caseVec[1])) || (static_cast<int>(caseVec[2])))
			result = true;
		else
			result = false;

		
		break;
		
	case '|':
		result = static_cast<int>(caseVec[0]) | static_cast<int>(caseVec[1]);
		break;


	//ands
	case '*':	//triple and.
		caseVec.push_back(static_cast<float>(rand()%2));

		if((static_cast<int>(caseVec[0])) && (static_cast<int>(caseVec[1])) && (static_cast<int>(caseVec[2])))
			result = true;
		else
			result = false;
		
		break;
	case '&':
	default:
		result = static_cast<int>(caseVec[0]) & static_cast<int>(caseVec[1]);
		break;	
	}
}

////////////////////////////////////////////////////////////////////////////////
//	FUNCTION:	TrainLite
/*!	\brief		Trains a given Dtree with a given opperation without user input.
**	\author		Nate Cleveland
*/
////////////////////////////////////////////////////////////////////////////////
void TrainLite(TestC45 &tree, char type__)
{

	TestC45::TestExample testEx;

	//create example
	CreateExample(testEx.m_caseVec, testEx.m_result, type__);
	bool response = tree.Think(testEx.m_caseVec);


	if(testEx.m_caseVec.size() == 2)
		printf("input: \"%.2f %c %.2f\" response: %d.",
			   testEx.m_caseVec[0], type__, testEx.m_caseVec[1], response);

	else if(testEx.m_caseVec.size() == 3)
		printf("input: \"%.2f %c %.2f %c %.2f  \" response: %d.",
			   testEx.m_caseVec[0], type__, testEx.m_caseVec[1], type__, testEx.m_caseVec[2], response);

	if(testEx.m_result == response)
		printf("\t\t\tCORRECT. \n");
	else
		printf("\t\t\tWRONG. \n");

	tree.GiveExample(testEx.m_caseVec, testEx.m_result);
}


////////////////////////////////////////////////////////////////////////////////
//	FUNCTION:	FileIO
/*!	\brief		Saves or loads a DTree depending on user input.
**	\author		Nate Cleveland
*/
////////////////////////////////////////////////////////////////////////////////
void FileIO(TestC45 &tree)
{
	char inputBuffer[512] = {0};
	char key = 0;

	printf("\n\nFile IO\n");
	printf("<s> to save this tree\n");
	printf("<l> to load a tree\n");
	printf("<q> or any other key to quit\n");

	switch(key = getch())
	{
	case 's':
	case 'S':
		
		printf("Save as: ");
		gets(inputBuffer);
		if(tree.save(inputBuffer))
			printf("Tree saved.");
		else
			printf("Failed to save.");
		break;

	case 'l':
	case 'L':
		printf("Load from: ");
		gets(inputBuffer);
		if(tree.load(inputBuffer))
			printf("Tree loaded.");
		else
			printf("Failed to load.");
	}

	printf("\n\n\n");
}

////////////////////////////////////////////////////////////////////////////////
//	FUNCTION:	ChangeType
/*!	\brief		Alters the opporation to train tree with.
**	\author		Nate Cleveland
*/
////////////////////////////////////////////////////////////////////////////////
void ChangeType(char& type__)
{
	char key = 0;
	printf("\n\nFitness Function Selection\n");
	printf("Change to what type?\n");
	printf("\tor '|', xor '^', and '&'\n");
	printf("\ttriple or '#', triple xor '%%', triple and '*'\n");

	switch(key = getch())
	{
	case '^':	//xor
	case '*':	//triple and
	case '%':	//triple xor
	case '#':	//tripple or
	case '|':	//or
	case '&':	//and
		type__ = key;
		break;	
	}

	printf("Fitness function used is now %c\n\n", type__);
}

////////////////////////////////////////////////////////////////////////////////
//	FUNCTION:	TrainTree
/*!	\brief		Trains a tree using given user input.
**	\author		Nate Cleveland
*/
////////////////////////////////////////////////////////////////////////////////
void TrainTree(TestC45 &tree)
{
	char type__ = '|';
	char inputBuffer[256] = {0};

	printf("<q>   or <esc> to quit,\n");
	printf("<l>   to learn,\n");
	printf("<0-9> to create #+1 examples,\n");
	printf("<f>   to save or load tree,\n");
	printf("<c>   to change fitness function from %c,\n", type__);
	printf("<d>   to clear all current examples,\n");
	printf("or any other key to create 1 example.\n");

	//loop as long as we don't get a null input
	while((inputBuffer[0] = getch())/* != 13*/)
	{
		switch(inputBuffer[0])
		{

		//quit the training.
		case 27:
		case 'Q':
		case 'q':
			return;

		//delete examples
		case 'd':
		case 'D':
			tree.m_exampleVec.clear();
			printf("Examples cleared.\n\n");
			break;

		//use file io
		case 'f':
		case 'F':
			FileIO(tree);
			break;

		//change fitness function
		case 'c':
		case 'C':
			ChangeType(type__);
			tree.ClearExampes();
			break;

		//have the tree learn from its examples.
		case 'l':
		case 'L':
			printf("...");
			tree.Learn();
			printf("Tree has completed learning.\n\n");
			break;

		//numbered traning
//		case '0':	Same as default
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		{
			for(int i = atoi(inputBuffer) + 1 ; i >0 ; i--)
				TrainLite(tree, type__);
			break;
		}

		//single training
		default:
			TrainLite(tree, type__);
			break;
		}//switch

		printf("\n\nCommand? <q/esc,l,0-9,c,f>\n");
	}//while
}//Train Tree


void ProfileTree(TestC45 &tree)
{
	char type__ = '%';
	TestC45::TestExample testEx;
	for(int i = 0 ; i < 10000 ; i++)
	{
		for(int j = 0; j < 10 ; j++)
		{
			CreateExample(testEx.m_caseVec, testEx.m_result, type__);
			tree.GiveExample(testEx.m_caseVec, testEx.m_result);
		}
		tree.Learn();
	}
}


int main(void)
{
	srand(time(NULL));

	TestC45 tree;
	TrainTree(tree);
//	ProfileTree(tree);

	return 0;
}
